<?php

CCore::Using('net.imap');
CCore::Using('net.imap.bodystructure');
CCore::Using('mime.message');

CCore::Using('labs.webmail');
CCore::Using('labs.webmail.folder');
CCore::Using('labs.webmail.header');
CCore::Using('labs.webmail.message');
CCore::Using('labs.webmail.attachment');
CCore::Using('labs.webmail.protocols.inc.interface');
CCore::Using('labs.webmail.protocols.inc.exception');

class CCoreLabsWebMailProtocolsIncImap implements ICoreLabsWebMailProtocolsInc
{
	const OBJECT_ERROR_CODE = 1300;

	/**
	 * @var array
	 */
	private $_aExceptionErrors = array(
		0 => 'Неизвестный exception',
		1 => 'Ошибка коннекта',
		2 => 'Ошибка аунтефикации',
		3 => 'Ошибка получения папок',
		4 => 'Ошибка выбора папки',
		5 => 'Ошибка запроса списка писем',
		6 => 'Ошибка запроса сообщений, пустой список уидов',
	);

	/**
	 * @var CCoreLabsWebMailAccount
	 */
	private $_oWebMailAccount;

	/**
	 * @var CCoreNetImap
	 */
	private $_oImap;

	/**
	 * @return CCoreLabsWebMailProtocolsIncImap
	 */
	public function __construct(CCoreLabsWebMailAccount $oWebMailAccount)
	{
		$this->_oWebMailAccount = $oWebMailAccount;
		$oImapConfig = new CCoreNetImapConfig(
			$oWebMailAccount->IncHost(), $oWebMailAccount->IncPort(),
			$oWebMailAccount->IncLogin(), $oWebMailAccount->incPassword(), 5, 5);

		$this->_oImap = new CCoreNetImap($oImapConfig);

 CCore::Using('base.followers.logger');
 CCore::Using('logger.file');
 $oLogger = new CCoreLoggerFile('c:/core.log.txt ');
 //$oLogger = new CCoreLoggerFile('c:/Users/RayMan/Documents/php_logs/core.log.txt ');
 $oFollower = new CCoreBaseFollowersLogger($oLogger);
 $this->_oImap->AddFollower($oFollower);

	}

	/**
	 * @return bool
	 */
	public function TestIncConnection()
	{
		if ($this->_oImap->ConnectAndLogin())
		{
			return $this->_oImap->LogoutAndDisconnect();
		}
		return false;
	}
	
	/**
	 * @return bool
	 */
	public function ForceCloseConnection()
	{
		$this->_oImap->LogoutAndDisconnect();
	}

	/**
	 * @return CCoreLabsWebMailFolderCollection
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function Folders()
	{
		$this->_connectAndLogin();

		$aImapFolders = $this->_oImap->FolderList();
		if (false === $aImapFolders)
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 3);
		}

		$aUnsortedWebMailFolders = array();
		foreach ($aImapFolders as /* @var $oImapFolder CCoreNetImapFolder */ &$oImapFolder)
		{
			$oWebMailFolder = new CCoreLabsWebMailFolder();
			$oWebMailFolder->InitByImapFolder($oImapFolder);
			$aUnsortedWebMailFolders[] =& $oWebMailFolder;
			unset($oImapFolder, $oWebMailFolder);
		}

		$oWebMailFolderCollection = new CCoreLabsWebMailFolderCollection();
		$oWebMailFolderCollection->InitByUnsortedFolderArray($aUnsortedWebMailFolders);
		unset($aUnsortedWebMailFolders);

		return $oWebMailFolderCollection;
	}


	/**
	 * @param string $sFolderParentFullName
	 * @param string $sFolderNameInUtf8
	 *
	 * @return bool
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function FolderCreate($sFolderParentFullName, $sFolderNameInUtf8)
	{
		$this->_connectAndLogin();

		$sDelimiter = '/';
		$aFolders = $this->_oImap->FolderList('', 'INBOX');
		if (isset($aFolders[0]))
		{
			$sDelimiter = $aFolders[0]->Delimiter;
		}

		$sFolderParentFullName .= (0 < strlen($sFolderParentFullName)) ? $sDelimiter : '';

		$sFullNameToCreate = $sFolderParentFullName.CCoreBaseUtils::Utf8ToUtf7Modified($sFolderNameInUtf8);

		$bIsFolderCreated =  $this->_oImap->FolderCreate($sFullNameToCreate);
		if ($bIsFolderCreated)
		{
			$this->_oImap->FolderSubscribe($sFullNameToCreate);
		}
		
		return $bIsFolderCreated;
	}

	/**
	 * @param string $sOldFolderFullName
	 * @param string $sFolderNameInUtf8
	 *
	 * @return bool
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function FolderRename($sOldFolderFullName, $sFolderNameInUtf8)
	{
		$this->_connectAndLogin();

		$sDelimiter = '/';
		$aFolders = $this->_oImap->FolderList('', 'INBOX');
		if (isset($aFolders[0]))
		{
			$sDelimiter = $aFolders[0]->Delimiter;
		}

		$aParentNames = explode($sDelimiter, $sOldFolderFullName);
		array_pop($aParentNames);
		
		$sFolderParentFullName = (0 < count($aParentNames)) ? implode($sDelimiter, $aParentNames) : '';

		$sNewFolderFullName = $sFolderParentFullName;
		$sNewFolderFullName .= (0 < strlen($sFolderParentFullName)) ? $sDelimiter : '';
		$sNewFolderFullName .= CCoreBaseUtils::Utf8ToUtf7Modified($sFolderNameInUtf8);

		$bIsFolderRenamed = $this->_oImap->FolderRename($sOldFolderFullName, $sNewFolderFullName);

		if ($bIsFolderRenamed)
		{
			$aListToReSubscribe = array();
			$aLSubList = $this->_oImap->FolderSubscribeList();
			if (is_array($aLSubList))
			{
				foreach ($aLSubList as /* @var $oLSubItemFolder CCoreNetImapFolder */ &$oLSubItemFolder)
				{
					if (0 === strpos($oLSubItemFolder->FullName, $sOldFolderFullName))
					{
						$aListToReSubscribe[] = $oLSubItemFolder->FullName;
					}
				}
			}

			foreach ($aListToReSubscribe as $sFolderFullName)
			{
				 $this->_oImap->FolderUnSubscribe($sFolderFullName);
				 $this->_oImap->FolderSubscribe($sNewFolderFullName.substr($sFolderFullName, strlen($sOldFolderFullName)));
			}
		}

		return $bIsFolderRenamed;
	}

	/**
	 * @param string $sFolderFullName
	 *
	 * @return bool
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function FolderDelete($sFolderFullName)
	{
		$this->_connectAndLogin();

		$bIsFolderDeletedSuccess = $this->_oImap->FolderDelete($sFolderFullName);
		if ($bIsFolderDeletedSuccess)
		{
			$this->_oImap->FolderUnSubscribe($sFolderFullName);
		}

		return $bIsFolderDeletedSuccess;
	}

	/**
	 * @param string $sFolderFullName
	 * @param int $iMessagePerPage
	 * @param int $iPage = 1
	 * @param string $sSearchDesc = ''
	 * @return CCoreLabsWebMailHeaderCollection
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function MessageHeadersList($sFolderFullName, $iMessagePerPage, $iPage = 1, $sSearchDesc = '')
	{
		$this->_connectAndLogin();

		$oWebMailHeaderCollection = new CCoreLabsWebMailHeaderCollection();

		$sSearchDesc = (null === $sSearchDesc) ? '' : $sSearchDesc;

		if (!$this->_oImap->FolderSelect($sFolderFullName))
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}
		
		$oCurrenFolderInfo = $this->_oImap->FolderCurrentInformation();
		if (null === $oCurrenFolderInfo)
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		$iMessagesCount = 0;
		$aRequestIds = $aIds = array();
		if (0 < $oCurrenFolderInfo->Exists)
		{
			$sSearchCriterias = 'ALL';
			if (!empty($sSearchDesc))
			{
				$sSearchCri = $this->_oImap->ImapEscapeString($sSearchDesc);
				$sSearchCriterias =
					'OR (OR (OR FROM "'.$sSearchCri.'" TO "'.$sSearchCri.'") SUBJECT "'.$sSearchCri.'") BODY "'.$sSearchCri.'"';

				$aIds = $this->_oImap->MessageSimpleSearch($sSearchCriterias, false, 'utf-8', 'ARRIVAL');
			}
			else
			{
				$aIds = range(1, $oCurrenFolderInfo->Exists);
			}

			if (is_array($aIds))
			{
				$aIds = array_reverse($aIds);
				$iMessagesCount = count($aIds);

				$iStart = ($iPage  - 1) * $iMessagePerPage;
				$iStart = (0 < $iStart) ? $iStart : 0;
				$aRequestIds = array_slice($aIds, $iStart, $iMessagePerPage);
			}
		}

		if (is_array($aRequestIds) && 0 < count($aRequestIds) && 0 < count($aIds))
		{
			$aInputFetchItems = array();
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::INDEX);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::UID);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::FLAGS);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::RFC822_SIZE);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::RFC822_HEADER);

			$aFetchResponse = $this->_oImap->Fetch($aInputFetchItems, implode(',', $aRequestIds), false);
			if (is_array($aFetchResponse))
			{
				$aFetchIndexArray = array();
				foreach ($aFetchResponse as /* @var $oFetchResponseItem CCoreNetImapFetchResponse */ &$oFetchResponseItem)
				{
					$iIndex = $oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::INDEX);
					$aFetchIndexArray[(int) $iIndex] =& $oFetchResponseItem;
					unset($oFetchResponseItem);
				}

				foreach ($aIds as $iId)
				{
					if (isset($aFetchIndexArray[$iId]))
					{
						$sHeaders =& $aFetchIndexArray[$iId]->GetFetchValue(ECoreNetImapFetch::RFC822_HEADER);
						$aFlags = $aFetchIndexArray[$iId]->GetFetchValue(ECoreNetImapFetch::FLAGS);
						$aFlags = is_array($aFlags) ? array_map('strtolower', $aFlags) : array();

						$oMessage = new CCoreMimeMessage();
						$oMessage->ParseFromString($sHeaders);

						$oWebMailHeader = new CCoreLabsWebMailHeader();
						$oWebMailHeader->Index = $aFetchIndexArray[$iId]->GetFetchValue(ECoreNetImapFetch::INDEX);
						$oWebMailHeader->Uid = $aFetchIndexArray[$iId]->GetFetchValue(ECoreNetImapFetch::UID);
						$oWebMailHeader->Subject = $oMessage->Subject();
						$oWebMailHeader->Date = $oMessage->RealDateAsObject();
						$oWebMailHeader->Size = $aFetchIndexArray[$iId]->GetFetchValue(ECoreNetImapFetch::RFC822_SIZE);
						$oWebMailHeader->From = $oMessage->From();
						$oWebMailHeader->To = $oMessage->To();
						$oWebMailHeader->Cc = $oMessage->Cc();
						$oWebMailHeader->Bcc = $oMessage->Bcc();
						$oWebMailHeader->HasAttachments = $oMessage->HasAttachments();
						$oWebMailHeader->IsUnread = !in_array(strtolower(ECoreNetImapMessageFlag::SEEN), $aFlags);
						$oWebMailHeader->IsFlagged = in_array(strtolower(ECoreNetImapMessageFlag::FLAGGED), $aFlags);
						$oWebMailHeader->IsAnswered = in_array(strtolower(ECoreNetImapMessageFlag::ANSWERED), $aFlags);
						$oWebMailHeader->Flags = $aFlags;

						$oWebMailHeaderCollection->Add($oWebMailHeader);
					}
				}
			}
			else
			{
				$this->_throwException('CCoreWebMailProtocolsIncException', 5);
			}
		}

		$oWebMailHeaderCollection->Page = $iPage;
		$oWebMailHeaderCollection->Folder = $sFolderFullName;
		$oWebMailHeaderCollection->Search = $sSearchDesc;
		$oWebMailHeaderCollection->Count = $iMessagesCount;
		$oWebMailHeaderCollection->Hash = md5(
			$oCurrenFolderInfo->FolderName.
			$oCurrenFolderInfo->Exists.
			$oCurrenFolderInfo->Recent.
			$oCurrenFolderInfo->Uidvalidity);

		return $oWebMailHeaderCollection;
	}


	/**
	 * @param string $sFolderFullName
	 * @param string $sUid
	 * @return string
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function MessageFullHeaders($sFolderFullName, $sUid)
	{
		$this->_connectAndLogin();

		$sResultHeaders = '';
		if (!$this->_oImap->FolderSelect($sFolderFullName))
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		$oCurrenFolderInfo = $this->_oImap->FolderCurrentInformation();
		if (null === $oCurrenFolderInfo)
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		if (0 < strlen($sUid))
		{
			$aInputFetchItems = array();
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::RFC822_HEADER);

			$aFetchResponse = $this->_oImap->Fetch($aInputFetchItems, $sUid, true);
			if (is_array($aFetchResponse))
			{
				foreach ($aFetchResponse as /* @var $oFetchResponseItem CCoreNetImapFetchResponse */ &$oFetchResponseItem)
				{
					$sResultHeaders =& $oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::RFC822_HEADER);
					unset($oFetchResponseItem);
					break;
				}
			}
			else
			{
				$this->_throwException('CCoreWebMailProtocolsIncException', 5);
			}
		}

		return $sResultHeaders;
	}

	/**
	 * @param string $sFolderFullName
	 * @param string $sUid
	 * @param mixed $mFormationCallback
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function MessageFullBodyThroughCallback($sFolderFullName, $sUid, $mFormationCallback)
	{
		$this->_connectAndLogin();

		if (!$this->_oImap->FolderSelect($sFolderFullName))
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		$oCurrenFolderInfo = $this->_oImap->FolderCurrentInformation();
		if (null === $oCurrenFolderInfo)
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		if (0 < strlen($sUid))
		{
			$oWebMailMessage = new CCoreLabsWebMailMessage();
			$oWebMailMessage->InitFormationCallback($mFormationCallback);

			$aInputFetchItems = array();
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::BODY_PEEK.'[]',
				array(&$oWebMailMessage, 'CallbackFullBodyStreamParse'));

			$aFetchResponse = $this->_oImap->Fetch($aInputFetchItems, $sUid, true);
			if (!is_array($aFetchResponse))
			{
				$this->_throwException('CCoreWebMailProtocolsIncException', 5);
			}
		}
	}

	/**
	 * @param string $sFolderFullName
	 * @return string
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function FolderHash($sFolderFullName)
	{
		$this->_connectAndLogin();

		if (!$this->_oImap->FolderSelect($sFolderFullName))
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		$oCurrenFolderInfo = $this->_oImap->FolderCurrentInformation();
		if (null === $oCurrenFolderInfo)
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		return md5($oCurrenFolderInfo->FolderName.
			$oCurrenFolderInfo->Exists.
			$oCurrenFolderInfo->Recent.
			$oCurrenFolderInfo->Uidvalidity);
	}

	/**
	 * @param string $sFolderFullName
	 * @param array $aUids
	 * @param bool $bIdSet
	 * @return bool
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function SetFlagged($sFolderFullName, $aUids, $bIsSet)
	{
		return $this->SetFlags($sFolderFullName, $aUids, ECoreNetImapMessageFlag::FLAGGED, $bIsSet);
	}

	/**
	 * @param string $sFolderFullName
	 * @param array $aUids
	 * @param bool $bIdSet
	 * @return bool
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function SetSeen($sFolderFullName, $aUids, $bIsSet)
	{
		return $this->SetFlags($sFolderFullName, $aUids, ECoreNetImapMessageFlag::SEEN, $bIsSet);
	}

	/**
	 * @param string $sFolderFullName
	 * @param array $aUids
	 * @param bool $bIdSet
	 * @return bool
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function SetFlags($sFolderFullName, $aUids, $sFlagName, $bIsSet)
	{
		$this->_connectAndLogin();

		if (!$this->_oImap->FolderSelect($sFolderFullName) || !$this->_oImap->FolderCurrentInformation())
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		$sIndexRange = implode(',', $aUids);

		$sStoreAction = ($bIsSet)
			? ECoreNetImapMessageStoreAction::ADD_FLAGS_SILENT : ECoreNetImapMessageStoreAction::REMOVE_FLAGS_SILENT;
		$aInputStoreItems = array($sFlagName);

		return $this->_oImap->MessageStoreFlag($sIndexRange, true, $aInputStoreItems, $sStoreAction);
	}

	/**
	 * @param string $sFolderFullName
	 * @param array $aUids
	 * @param mixed $mFormationCallback
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function MessagesThroughCallback($sFolderFullName, $aUids, $mFormationCallback)
	{
		$this->_connectAndLogin();

		if (!$this->_oImap->FolderSelect($sFolderFullName))
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		$oCurrenFolderInfo = $this->_oImap->FolderCurrentInformation();
		if (null === $oCurrenFolderInfo)
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		if (is_array($aUids) && 0 < count($aUids))
		{
			$aInputFetchItems = array();
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::INDEX);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::UID);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::FLAGS);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::RFC822_SIZE);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::RFC822_HEADER);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::BODYSTRUCTURE);

			$aFetchResponse = $this->_oImap->Fetch($aInputFetchItems, implode(',', $aUids), true);
			if (is_array($aFetchResponse))
			{
				foreach ($aFetchResponse as /* @var $oFetchResponseItem CCoreNetImapFetchResponse */ &$oFetchResponseItem)
				{
					$sCurrentUid = $oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::UID);
					$sHeaders =& $oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::RFC822_HEADER);
					$aFlags = $oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::FLAGS);
					$aFlags = is_array($aFlags) ? array_map('strtolower', $aFlags) : array();

					$oMessage = new CCoreMimeMessage();
					$oMessage->ParseFromString($sHeaders);

					$oWebMailMessage = new CCoreLabsWebMailMessage();
					$oWebMailMessage->InitFormationCallback($mFormationCallback);

					$oWebMailMessage->Index = $oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::INDEX);
					$oWebMailMessage->Uid = $sCurrentUid;
					$oWebMailMessage->Folder = $sFolderFullName;
					$oWebMailMessage->Subject = $oMessage->Subject();
					$oWebMailMessage->Date = $oMessage->RealDateAsObject();
					$oWebMailMessage->Size = $oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::RFC822_SIZE);
					$oWebMailMessage->From = $oMessage->From();
					$oWebMailMessage->To = $oMessage->To();
					$oWebMailMessage->Cc = $oMessage->Cc();
					$oWebMailMessage->Bcc = $oMessage->Bcc();
					$oWebMailMessage->IsUnread = !in_array(strtolower(ECoreNetImapMessageFlag::SEEN), $aFlags);
					$oWebMailMessage->IsFlagged = in_array(strtolower(ECoreNetImapMessageFlag::FLAGGED), $aFlags);
					$oWebMailMessage->Flags = $aFlags;
					$oWebMailMessage->Charset = $oMessage->GetCharset();
					$oWebMailMessage->BodyStrucrute = CCoreNetImapBodyStructure::Parse(
						$oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::BODYSTRUCTURE),
						$oWebMailMessage->Charset);

					$oBodyStrucruteAttachments = $oWebMailMessage->BodyStrucrute->SearchAttachmentsParts();
					if ($oBodyStrucruteAttachments && 0 < count($oBodyStrucruteAttachments))
					{
						foreach ($oBodyStrucruteAttachments as /* @var $oBodyStrucruteAttachment CCoreNetImapBodyStructure */ $oBodyStrucruteAttachment)
						{
							$oWebMailMessage->Attachments[] = new CCoreLabsWebMailAttachment(
								$oBodyStrucruteAttachment->PartID(),
								$oBodyStrucruteAttachment->FileName(),
								$oBodyStrucruteAttachment->ContentType(),
								$oBodyStrucruteAttachment->EstimatedSize(),
								$oBodyStrucruteAttachment->MailEncodingName(),
								$oBodyStrucruteAttachment->ContentID()
							);
						}
					}

					$oBodyStrucrutePlain = $oWebMailMessage->BodyStrucrute->SearchPlainPart();
					$oBodyStrucruteHtml = $oWebMailMessage->BodyStrucrute->SearchHtmlPart();

					$aSingleInputFetchItems = array();
					if ($oBodyStrucruteHtml)
					{
						CCoreNetImapFetchItem::AddToArray($aSingleInputFetchItems,
							ECoreNetImapFetch::BODY_PEEK.'['.$oBodyStrucruteHtml->PartID().']',
							array(&$oWebMailMessage, 'CallbackHtmlTextStreamParse'));
					}
				
					if ($oBodyStrucrutePlain)
					{
						CCoreNetImapFetchItem::AddToArray($aSingleInputFetchItems,
							ECoreNetImapFetch::BODY_PEEK.'['.$oBodyStrucrutePlain->PartID().']',
							array(&$oWebMailMessage, 'CallbackPlainTextStreamParse'));
					}
					
					if (0 < count($aSingleInputFetchItems))
					{
						$this->_oImap->Fetch($aSingleInputFetchItems, $sCurrentUid, true);
					}
				}
			}
			else
			{
				$this->_throwException('CCoreWebMailProtocolsIncException', 6);
			}
		}
	}

	/**
	 * @param string $sFolderFullName
	 * @param string $sUid
	 * @param string $sMimeIndex
	 * @param mixed $mFormationCallback
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	public function AttachmentThroughCallback($sFolderFullName, $sUid, $sMimeIndex, $mFormationCallback)
	{
		$this->_connectAndLogin();

		if (!$this->_oImap->FolderSelect($sFolderFullName))
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		$oCurrenFolderInfo = $this->_oImap->FolderCurrentInformation();
		if (null === $oCurrenFolderInfo)
		{
			$this->_throwException('CCoreWebMailProtocolsIncException', 4);
		}

		if (!empty($sUid))
		{
			$aInputFetchItems = array();
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::INDEX);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::UID);
			CCoreNetImapFetchItem::AddToArray($aInputFetchItems, ECoreNetImapFetch::BODYSTRUCTURE);

			$aFetchResponse = $this->_oImap->Fetch($aInputFetchItems, $sUid, true);
			if (is_array($aFetchResponse) && 1 === count($aFetchResponse))
			{
				foreach ($aFetchResponse as /* @var $oFetchResponseItem CCoreNetImapFetchResponse */ &$oFetchResponseItem)
				{
					$sCurrentUid = $oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::UID);

					$oBodyStrucrute = CCoreNetImapBodyStructure::Parse(
						$oFetchResponseItem->GetFetchValue(ECoreNetImapFetch::BODYSTRUCTURE));

					$aAttachments = array();
					$oBodyStrucruteAttachments = $oBodyStrucrute->SearchAttachmentsParts();
					if ($oBodyStrucruteAttachments && 0 < count($oBodyStrucruteAttachments))
					{
						foreach ($oBodyStrucruteAttachments as /* @var $oBodyStrucruteAttachment CCoreNetImapBodyStructure */ $oBodyStrucruteAttachment)
						{
							$aAttachments[$oBodyStrucruteAttachment->PartID()] = new CCoreLabsWebMailAttachment(
								$oBodyStrucruteAttachment->PartID(),
								$oBodyStrucruteAttachment->FileName(),
								$oBodyStrucruteAttachment->ContentType(),
								$oBodyStrucruteAttachment->EstimatedSize(),
								$oBodyStrucruteAttachment->MailEncodingName(),
								$oBodyStrucruteAttachment->ContentID()
							);
						}
					}

					if (isset($aAttachments[$sMimeIndex]))
					{
						$aAttachments[$sMimeIndex]->InitFormationCallback($mFormationCallback);

						$aInputFetchItems = array();
						CCoreNetImapFetchItem::AddToArray($aInputFetchItems,
							ECoreNetImapFetch::BODY_PEEK.'['.$sMimeIndex.']',
							array(&$aAttachments[$sMimeIndex], 'CallbackAttachmentStreamParse'));

						if (!is_array($this->_oImap->Fetch($aInputFetchItems, $sUid, true)))
						{
							$this->_throwException('CCoreWebMailProtocolsIncException', 6);
						}
					}
				}
			}
			else
			{
				$this->_throwException('CCoreWebMailProtocolsIncException', 6);
			}
		}
	}

	/**
	 * @param string $sFolderFullName
	 * @param string $sFileName
	 *
	 * @throw CCoreWebMailException
	 */
	public function AppendMailFromFile($sFolderFullName, $sFileName)
	{
		$this->_connectAndLogin();

		return $this->_oImap->MessageAppend(file_get_contents($sFileName), $sFolderFullName);
	}

	/**
	 * @return bool
	 *
	 * @throw CCoreWebMailProtocolsIncException
	 */
	private function _connectAndLogin()
	{
		if (!$this->_oImap->IsConnected())
		{
			if (!$this->_oImap->Connect())
			{
				$this->_throwException('CCoreWebMailProtocolsIncException', 1);
			}
			
			if (!$this->_oImap->Login())
			{
				$this->_throwException('CCoreWebMailProtocolsIncException', 2);
			}
		}
		
		return true;
	}

	/**
	 * @param string $sExceptionName
	 * @param int $iCode
	 * @return int
	 */
	private function _throwException($sExceptionName, $iCode)
	{
		if (!isset($this->_aExceptionErrors[$iCode]))
		{
			$iCode = 0;
		}

		throw new $sExceptionName($this->_aExceptionErrors[$iCode], self::OBJECT_ERROR_CODE + $iCode);
	}
}
